#!/usr/bin/env bash

# Copyright (c) Open Enclave SDK contributors.
# Licensed under the MIT License.

set -o errexit

##==============================================================================
##
## Helper method to work around idiosyncracy in MinGW/MSYS (used by Git Bash)
##
##  - MSYS tries to convert POSIX paths to Win32 paths when passing args to
##    tools not compiled for MSYS(e.g. openssl).
##  - This method converts '/C=US/ST=CA' to '//C=US\ST=CA' to avoid this. It
##    does this to exploit another specific idiosyncracy of MSYS arg inference.
##  - MSYS treats an argument starting with >=2 '/' as an escaped Windows-style
##    switch and strips extra leading '/'. It also converts any following '\'
##    to '/' for consistency with the switch style, hence the converted format.
##  - The rest of the arg cannot already be followed by '/' with, otherwise MSYS
##    interprets the arg as an UNC path and leaves it unchanged (e.g. //foo/bar)
##
## See http://www.mingw.org/wiki/Posix_path_conversion for details.
##
##==============================================================================
convert_slashes_in_dn()
{
    # Replace all '/' with '\' characters
    local RESULT=${1//\//\\}

    # Replace leading '\' character with '//'
    local RESULT=${RESULT/\\/\/\/}

    echo "${RESULT}"
}

# Process command line options
SOURCE_DIR="$1"
TARGET_DIR="$2"
BUILD_OPT="$3"

case ${BUILD_OPT} in
    --gitbash)
    USE_MINGW=1
    ;;

    --bash)
    ;;

    *)
    echo "$0: unknown BUILD_OPT=${BUILD_OPT}"
    exit 1
    ;;
esac

TEST_ROOT_DN="/C=US/ST=Ohio/L=Columbus/O=Acme Company/OU=Acme/CN=Root"
TEST_CA_DN="/C=US/ST=Ohio/L=Columbus/O=Acme Company/OU=Acme/CN=Intermediate CA"
TEST_LEAF1_DN="/C=US/ST=Ohio/L=Columbus/O=Acme Company/OU=Acme/CN=Leaf 1"
TEST_LEAF2_DN="/C=US/ST=Ohio/L=Columbus/O=Acme Company/OU=Acme/CN=Leaf 2"

if [[ ${USE_MINGW} -eq 1 ]]; then
    TEST_ROOT_DN=$(convert_slashes_in_dn "${TEST_ROOT_DN}")
    TEST_CA_DN=$(convert_slashes_in_dn "${TEST_CA_DN}")
    TEST_LEAF1_DN=$(convert_slashes_in_dn "${TEST_LEAF1_DN}")
    TEST_LEAF2_DN=$(convert_slashes_in_dn "${TEST_LEAF2_DN}")
fi

# Create target folder if it does not already exist
mkdir -p "${TARGET_DIR}"

# x509 V3 extensions required to be able to validate cert chains using a self signed root cert and intermediate cert signed by the root cert.
# SSL1.1 no longer allows signing certs without the necessary v3 extensions.
cp -u "${SOURCE_DIR}/root_v3.ext" "${TARGET_DIR}"
cp -u "${SOURCE_DIR}/intermediate_v3.ext" "${TARGET_DIR}"
cp -u "${SOURCE_DIR}/intermediate.cnf" "${TARGET_DIR}"
cp -u "${SOURCE_DIR}/intermediate2.cnf" "${TARGET_DIR}"
cp -u "${SOURCE_DIR}/root.cnf" "${TARGET_DIR}"
cp -u "${SOURCE_DIR}/root2.cnf" "${TARGET_DIR}"

# ================ Generate test CRLs and certificates ===============
# Create the root CA private key and self-signed root CA cert
openssl genrsa -out root.key.pem
openssl req -new -x509 -key root.key.pem -out root.cert.pem -days 3650 -subj "${TEST_ROOT_DN}"

# We want to generate certificates used in this tests with at least one second apart to make it possible to sort those certificate by time
# "Not Before" of a x509 certificate, which has time resolution up to a second
sleep 1

# Create the intermediate CA certificate, signed by the root CA
openssl genrsa -out intermediate.key.pem
openssl req -new -key intermediate.key.pem -out intermediate.csr -subj "${TEST_CA_DN}"
openssl x509 -req -in intermediate.csr -CA root.cert.pem -CAkey root.key.pem -CAcreateserial -out intermediate.cert.pem -days 3650 -extfile intermediate_v3.ext

sleep 1

# Create leaf certificates signed by the intermediate CA
echo 'Creating leaf certificates signed by the intermediate CA ...'
openssl genrsa -out leaf1.key.pem
openssl req -new -key leaf1.key.pem -out leaf1.csr -subj "${TEST_LEAF1_DN}"
openssl x509 -req -in leaf1.csr -CA intermediate.cert.pem -CAkey intermediate.key.pem -CAcreateserial -out leaf1.cert.pem -days 3650

sleep 1

openssl genrsa -out leaf2.key.pem
openssl req -new -key leaf2.key.pem -out leaf2.csr -subj "${TEST_LEAF2_DN}"
openssl x509 -req -in leaf2.csr -CA intermediate.cert.pem -CAkey intermediate.key.pem -CAcreateserial -out leaf2.cert.pem -days 3650

# Setup certificate revocation lists (CRLs) for the following test cases
# - root_crl1 and root_crl2 are issued by root
# - root_crl1 revokes no certificates
# - root_crl2 revokes intermediate cert
# - intermediate_crl1 and intermediate_crl2 are issued by intermediate
# - intermediate_crl1 revokes no certificates
# - intermediate_crl2 revokes leaf2

rm -f root_index.txt
touch root_index.txt
rm -f root_index2.txt
touch root_index2.txt
rm -f intermediate_index.txt
touch intermediate_index.txt
rm -f intermediate_index2.txt
touch intermediate_index2.txt
echo "00" > root_crl_number
echo "00" > root_crl_number2
echo "00" > intermediate_crl_number
echo "00" > intermediate_crl_number2

# Generate the root and intermediate CA CRLs
openssl ca -gencrl -config root.cnf -out root_crl1.pem
openssl ca -gencrl -config root2.cnf -out root_crl2.pem
openssl ca -gencrl -config intermediate.cnf -out intermediate_crl1.pem
openssl ca -gencrl -config intermediate2.cnf -out intermediate_crl2.pem

# Revoke the intermediate CA and leaf certs
openssl ca -revoke intermediate.cert.pem -keyfile root.key.pem -cert root.cert.pem -config root2.cnf
openssl ca -revoke leaf2.cert.pem -keyfile intermediate.key.pem -cert intermediate.cert.pem -config intermediate2.cnf

# Generate updated CRL lists with the revocations
openssl ca -gencrl -config root2.cnf -out root_crl2.pem
openssl ca -gencrl -config intermediate2.cnf -out intermediate_crl2.pem

# Convert the CRLs from pem to der format
openssl crl -inform pem -outform der -in root_crl1.pem -out root_crl1.der
openssl crl -inform pem -outform der -in root_crl2.pem -out root_crl2.der
openssl crl -inform pem -outform der -in intermediate_crl1.pem -out intermediate_crl1.der
openssl crl -inform pem -outform der -in intermediate_crl2.pem -out intermediate_crl2.der
